package com.mt.roll.core.vo;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.mt.roll.core.base.BaseVo;
import com.mt.roll.core.exception.ApiException;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.beans.BeanUtils;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * 分页vo转换类
 * 对象转换默认自动转换，也可以自定义转换：重写PageVo.ConvertVo接口默认方法即可
 *
 * @author Mr.ZhangShi
 * @date 2018/11/1 14:27
 */
@Data
@ApiModel("分页视图对象")
public class PageVo<T extends PageVo.ConvertVo> extends BaseVo {

    /**
     * 数据
     */
    @ApiModelProperty("数据")
    private List<T> records;

    /**
     * 总数
     */
    @ApiModelProperty("总数")
    private long total;

    /**
     * 总页数
     */
    @ApiModelProperty("总页数")
    private long pages;

    /**
     * 每页记录数
     */
    @ApiModelProperty("每页记录数")
    private long size;

    /**
     * 当前页
     */
    @ApiModelProperty("当前页")
    private long current;

    public <R> PageVo(IPage<R> page, Class<T> cls) {
        this.total = page.getTotal();
        this.pages = page.getPages();
        this.size = page.getSize();
        this.current = page.getCurrent();
        if (CollectionUtils.isNotEmpty(page.getRecords())) {
            posConvertVos(page.getRecords(), cls);
        }
    }

    /**
     * pojoList转化为voList
     *
     * @param pos     原对象列表
     * @param voClass 目标对象class
     * @param <R>     原对象
     */
    public <R> void posConvertVos(List<R> pos, Class<T> voClass) {
        this.records = new ArrayList<>();
        try {
            for (R po : pos) {
                T vo = newInstance(voClass);
                vo.convertPoToVo(po);
                records.add(vo);
            }
        } catch (Exception e) {
            throw new ApiException("对象转换异常", e);
        }
    }

    /**
     * 实例化
     *
     * @param voClass
     * @return
     */
    private T newInstance(Class<T> voClass) {
        try {
            T vo;
            //如果包含builder方法则为使用lombok.Builder注解的类，该注解只在编译期间有效，编译后的class中无法获取该注解
            try {
                Method builder = voClass.getDeclaredMethod("builder");
                Object invoke = builder.invoke(null, null);
                vo = (T) invoke.getClass().getDeclaredMethod("build").invoke(invoke);
            } catch (NoSuchMethodException e) {
                vo = voClass.newInstance();
            }
            return vo;
        } catch (Exception e) {
            throw new ApiException("对象拷贝异常", e);
        }
    }

    public interface ConvertVo {

        /**
         * 自定义转换
         *
         * @param po
         */
        default void convertPoToVo(Object po) {
            defaultConvertPoToVo(po, this);
        }
    }

    /**
     * 默认对象转换方法
     *
     * @param po 原对象
     * @param vo 目标对象
     */
    private static void defaultConvertPoToVo(Object po, Object vo) {
        BeanUtils.copyProperties(po, vo);
    }

}
